
//_________________________________Copyright (c) 2009,Mapabc Co.,Ltd_____________________________
//                                       All rights reserved.
// 
//   文件名称：iphonefile.mm
//   文件标识：见配置管理计划书
//   描    述：iphone文件操作
// 
//   当前版本：1.0
//   作    者：张小刚
//   完成日期：2022.02.08
//_______________________________________________________________________________________________

#include "osapi.h"

#if defined IOS || defined MAC

#include <Foundation/Foundation.h>

#define MAXLEN_OF_PATH 256
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

/**
 * @brief 创建目录
 * @param cPathName 目录名称（编码：UTF-8）
 * @return  0      创建成功
 * @return -1      创建失败
 */
int32_t osCreateDirectory(const char *cPathName)
{
	if(nullptr==cPathName)
	{
		return -1;
	}

	NSString *nsPathName=[[NSString alloc]initWithUTF8String:cPathName];
	if([nsPathName isEqualToString:@""])
	{
		return -1;
	}

	NSError *nsError=nil;
	const BOOL ret=[[NSFileManager defaultManager] createDirectoryAtPath:nsPathName 
		withIntermediateDirectories:NO attributes:nil error:&nsError];
	if(NO==ret||nsError)
	{
		return -1;
	}

	return 0;
}

/**
 * @brief 创建目录
 * @param cPathName 目录名称（编码：UTF-16）
 * @return  0      创建成功
 * @return -1      创建失败
 */
int32_t osCreateDirectory(const char16_t *cPathName)
{
	if(nullptr==cPathName)
	{
		return -1;
	}
	char u8PathName[256]={0};
	if(osConvertToUTF8(cPathName,u8PathName,256)<=0)
	{
		return -1;
	}
	return osCreateDirectory(u8PathName);
}

/**
 * @brief 创建目录
 * @param cPathName 目录名称（编码：UTF-32）
 * @return  0      创建成功
 * @return -1      创建失败
 */
int32_t osCreateDirectory(const char32_t *cPathName)
{
	if(nullptr==cPathName)
	{
		return -1;
	}
	char u8PathName[256]={0};
	if(osConvertToUTF8(cPathName,u8PathName,256)<=0)
	{
		return -1;
	}
	return osCreateDirectory(u8PathName);
}

/**
 * @brief 获取可执行程序的全路径名称（包含可执行程序名称）
 * @param fileName  存储可执行程序全路径名称（编码：UTF-8）
 * @param size      存储区域大小
 * @return 0        失败
 * @return !0       返回复制到fileName的实际字符数量
 */
uint32_t osGetModuleFileName(char *fileName,const uint32_t size)
{
	if(nullptr==fileName||0==size)
	{
		return 0;
	}

	NSString *bundleContainterPath=[[NSBundle mainBundle] bundlePath];
	if([bundleContainterPath isEqualToString:@""])
	{
		return 0;
	}

	const char *path=[bundleContainterPath UTF8String];
	if(nullptr==path)
	{
		return 0;
	}

	const int32_t len=osstrlen(path);
	if(len<=0)
	{
		return 0;
	}
	
	const int32_t factLen=(len>=size?size-1:len);
	osstrncpy(fileName,path,factLen);

	return (uint32_t)factLen;
}

/**
 * @brief 获取可执行程序的全路径名称（包含可执行程序名称）
 * @param fileName  存储可执行程序全路径名称（编码: UTF-16）
 * @param size      存储区域大小
 * @return 0        失败
 * @return !0       返回复制到fileName的实际字符数量
 */
uint32_t osGetModuleFileName(char16_t *fileName,const uint32_t size)
{
	if(nullptr==fileName||0==size)
	{
		return 0;
	}

	char u8FileName[256]={0x00};
	if(0==osGetModuleFileName(u8FileName,256))
	{
		return 0;
	}

	return osConvertToUTF16(u8FileName,fileName,size);
}

/**
 * @brief 获取可执行程序的全路径名称（包含可执行程序名称）
 * @param fileName  存储可执行程序全路径名称（编码：UTF-32）
 * @param size      存储区域大小
 * @return 0        失败
 * @return !0       返回复制到fileName的实际字符数量
 */
uint32_t osGetModuleFileName(char32_t *fileName,const uint32_t size)
{
	if(nullptr==fileName||0==size)
	{
		return 0;
	}

	char u8FileName[256]={0x00};
	if(0==osGetModuleFileName(u8FileName,256))
	{
		return 0;
	}

	return osConvertToUTF32(u8FileName,fileName,size);
}

/**
 * @brief 获取指定目录的上一层
 * @param cPath       指定目录（编码：UTF-8）
 * @param cLastPath   上一层目录（编码：UTF-8）
 * @param size        存储上一层目录空间尺寸
 * @return  0         失败
 * @return  !0        返回复制到cLastPath的实际字符数量
 */
static uint32_t osGetLastDirectory(const char *cPath,char *cLastPath,const uint32_t size)
{
	if(nullptr==cPath||nullptr==cLastPath||0==size)
	{
		return 0;
	}
	memset(cLastPath,0,size*sizeof(char));

	int32_t lPostion=-1;
	const int32_t len=osstrlen(cPath);
	for(int32_t i=0;i<len;i++)
	{
		if('\\'==cPath[i]||'/'==cPath[i])
		{
			lPostion=i;
		}
	}

	if(lPostion<0||static_cast<uint32_t>(lPostion)>=size)
	{
		return 0;
	}

	for(int32_t i=0;i<lPostion;i++)
	{
		cLastPath[i]=cPath[i];
	}
	
	return static_cast<uint32_t>(lPostion);
}

/**
 * @brief 获取指定目录的上一层
 * @param cPath       指定目录（编码：UTF-16）
 * @param cLastPath   上一层目录（编码：UTF-16）
 * @param size        存储上一层目录空间尺寸
 * @return  0         失败
 * @return  !0        返回复制到cLastPath的实际字符数量
 */
static uint32_t osGetLastDirectory(const char16_t *cPath,char16_t *cLastPath,const uint32_t size)
{
	if(nullptr==cPath||nullptr==cLastPath||0==size)
	{
		return 0;
	}
	memset(cLastPath,0,size*sizeof(char16_t));

	int32_t lPostion=-1;
	const int32_t len=osstrlen(cPath);
	for(int32_t i=0;i<len;i++)
	{
		if(u'\\'==cPath[i]||u'/'==cPath[i])
		{
			lPostion=i;
		}
	}

	if(lPostion<0||static_cast<uint32_t>(lPostion)>=size)
	{
		return 0;
	}

	for(int32_t i=0;i<lPostion;i++)
	{
		cLastPath[i]=cPath[i];
	}

	return static_cast<uint32_t>(lPostion);
}

/**
 * @brief 获取指定目录的上一层
 * @param cPath       指定目录（编码：UTF-32）
 * @param cLastPath   上一层目录（编码：UTF-32）
 * @param size        存储上一层目录空间尺寸
 * @return  0         失败
 * @return  !0        返回复制到cLastPath的实际字符数量
 */
static uint32_t osGetLastDirectory(const char32_t *cPath,char32_t *cLastPath,const uint32_t size)
{
	if(nullptr==cPath||nullptr==cLastPath||0==size)
	{
		return 0;
	}
	memset(cLastPath,0,size*sizeof(char32_t));

	int32_t lPostion=-1;
	const int32_t len=osstrlen(cPath);
	for(int32_t i=0;i<len;i++)
	{
		if(U'\\'==cPath[i]||U'/'==cPath[i])
		{
			lPostion=i;
		}
	}

	if(lPostion<0||static_cast<uint32_t>(lPostion)>=size)
	{
		return 0;
	}

	for(int32_t i=0;i<lPostion;i++)
	{
		cLastPath[i]=cPath[i];
	}

	return static_cast<uint32_t>(lPostion);
}

/**
 * @brief 获取可执行程序的全路径
 * @param cPath    存储可执行程序全路径（编码：UTF-8）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetExePath(char *cPath,const uint32_t size)
{
	if(nullptr==cPath||0==size)
	{
		return 0;
	}

	char fileName[256]={0};
	if(0==osGetModuleFileName(fileName,256))
	{
		return 0;
	}
	
	return osGetLastDirectory(fileName,cPath,size);
}

/**
 * @brief 获取可执行程序的全路径
 * @param cPath    存储可执行程序全路径（编码：UTF-16）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetExePath(char16_t *cPath,const uint32_t size)
{
	if(nullptr==cPath||0==size)
	{
		return 0;
	}

	char16_t fileName[256]={0};
	if(0==osGetModuleFileName(fileName,256))
	{
		return 0;
	}

	return osGetLastDirectory(fileName,cPath,size);
}

/**
 * @brief 获取可执行程序的全路径
 * @param cPath    存储可执行程序全路径（编码：UTF-32）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetExePath(char32_t *cPath,const uint32_t size)
{
	if(nullptr==cPath||0==size)
	{
		return 0;
	}

	char32_t fileName[256]={0};
	if(0==osGetModuleFileName(fileName,256))
	{
		return 0;
	}

	return osGetLastDirectory(fileName,cPath,size);
}

/**
 * @brief 获得存放资源的目录,默认在windows、Linux下获得可执行程序所在的上一个目录,
 *        在symbian和iphone平台下指定可读写的目录即可(在osapi实现osGetModulePath)
 * @param cPath    存储资源路径（编码：UTF-8）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetModulePath(char *cPath,const uint32_t size)
{
	if(nullptr==cPath||0==size)
	{
		return 0;
	}

	NSArray *nsPaths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
	if(nil==nsPaths||0==[nsPaths count])
	{
		return 0;
	}

	NSString *nsDocPath=[nsPaths objectAtIndex:0];
	if(nil==nsDocPath||[nsDocPath isEqualToString:@""])
	{
		return 0;
	}

	const char *path=[nsDocPath UTF8String];
	if(nullptr==path)
	{
		return 0;
	}

	const int32_t len=osstrlen(path);
	if(len<=0)
	{
		return 0;
	}
	
	const int32_t factLen=(len>=size?size-1:len);
	osstrncpy(cPath,path,factLen);

	return (uint32_t)factLen;
}

/**
 * @brief 获得存放资源的目录,默认在windows、Linux下获得可执行程序所在的上一个目录,
 *        在symbian和iphone平台下指定可读写的目录即可(在osapi实现osGetModulePath)
 * @param cPath    存储资源路径（编码：UTF-16）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetModulePath(char16_t *cPath,const uint32_t size)
{
	if(nullptr==cPath||0==size)
	{
		return 0;
	}

	char docPath[256]={0x00};
	if(0==osGetModulePath(docPath,256))
	{
		return 0;
	}

	return osConvertToUTF16(docPath,cPath,size);
}

/**
 * @brief 获得存放资源的目录,默认在windows、Linux下获得可执行程序所在的上一个目录,
 *        在symbian和iphone平台下指定可读写的目录即可(在osapi实现osGetModulePath)
 * @param cPath    存储资源路径（编码：UTF-32）
 * @param size     存储区域大小
 * @return 0       失败
 * @return !0      返回复制到cPath的实际字符数量
 */
uint32_t osGetModulePath(char32_t *cPath,const uint32_t size)
{
	if(nullptr==cPath||0==size)
	{
		return 0;
	}
	
	char docPath[256]={0x00};
	if(0==osGetModulePath(docPath,256))
	{
		return 0;
	}
	
	return osConvertToUTF32(docPath,cPath,size);
}

/**
 * @brief 打开文件
 * @param   cFileName    文件名称（编码：UTF-8）     
 * @param   bReadOnly    只读标志
 * @param   bCreateNew   新建标志
 * @return  nullptr     失败
 * @return !nullptr    文件句柄
 * @note   如果当前为安卓系统，并且期望访问assets目录下文件，则需要将
 *         cFileName设置为如下格式"assets:目录"
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osOpenFile(const char *cFileName,const bool bReadOnly,const bool bCreateNew)
{
	if(nullptr==cFileName)
	{
		return nullptr;
	}

	NSString *nsFileName=[[NSString alloc]initWithUTF8String:cFileName];
	if(nil==nsFileName||[nsFileName isEqualToString:@""])
	{
		return nullptr;
	}

	if(bCreateNew)
	{
		NSFileManager *fileManager=[NSFileManager defaultManager];
		if(nil==fileManager)
		{
			return nullptr;
		}
		if(NO==[fileManager createFileAtPath:nsFileName contents:nil attributes:nil])
		{
			return nullptr;
		}
	}

	if (bReadOnly)
	{
		NSFileHandle *fileHandle=[NSFileHandle fileHandleForReadingAtPath:nsFileName];
		if(nil==fileHandle)
		{
			return nullptr;
		}
		else
		{
			return (__bridge void*)fileHandle;
		}
	}
	else
	{
		NSFileHandle *fileHandle=[NSFileHandle fileHandleForUpdatingAtPath:nsFileName];
		if(nil==fileHandle)
		{
			return nullptr;
		}
		else
		{
			return (__bridge void*)fileHandle;
		}
	}
}

/**
 * @brief 打开文件
 * @param   cFileName    文件名称（编码：UTF-16）     
 * @param   bReadOnly    只读标志
 * @param   bCreateNew   新建标志
 * @return  nullptr     失败
 * @return !nullptr    文件句柄
 * @note   如果当前为安卓系统，并且期望访问assets目录下文件，则需要将
 *         cFileName设置为如下格式"assets:目录"
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osOpenFile(const char16_t *cFileName,const bool bReadOnly,const bool bCreateNew)
{
	if(nullptr==cFileName)
	{
		return nullptr;
	}

	char u8FileName[256]={0x00};
	if(osConvertToUTF8(cFileName,u8FileName,256)<=0)
	{
		return nullptr;
	}

	return osOpenFile(u8FileName,bReadOnly,bCreateNew);
}

/**
 * @brief 打开文件
 * @param   cFileName    文件名称（编码：UTF-32）     
 * @param   bReadOnly    只读标志
 * @param   bCreateNew   新建标志
 * @return  nullptr     失败
 * @return !nullptr    文件句柄
 * @note   如果当前为安卓系统，并且期望访问assets目录下文件，则需要将
 *         cFileName设置为如下格式"assets:目录"
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osOpenFile(const char32_t *cFileName,const bool bReadOnly,const bool bCreateNew)
{
	if(nullptr==cFileName)
	{
		return nullptr;
	}

	char u8FileName[256]={0x00};
	if(osConvertToUTF8(cFileName,u8FileName,256)<=0)
	{
		return nullptr;
	}

	return osOpenFile(u8FileName,bReadOnly,bCreateNew);
}

/**
 * @brief 关闭指定文件
 * @param hCom      文件句柄
 */
void osCloseFile(void **hCom)
{
	if(nullptr!=*hCom)
	{
		osFclose(*hCom);
		*hCom=nullptr;
	}
}

/**
 * @brief 检测指定目录是否存在
 * @param cPath 指定目录（编码：UTF-8）
 * @return true  目录存在
 * @return false 目录不存在
 */
bool osIsPathExist(const char *cPath)
{
	if(nullptr==cPath)
	{
		return false;
	}
	
	NSString *nsPath=[[NSString alloc]initWithUTF8String:cPath];
	if(nil==nsPath||[nsPath isEqualToString:@""])
	{
		return false;
	}

	NSFileManager *nsFileManager=[NSFileManager defaultManager];
	if(nil==nsFileManager)
	{
		return false;
	}

	BOOL bDir=NO;
	BOOL bExisted=[nsFileManager fileExistsAtPath:nsPath isDirectory:&bDir];
	if(NO!=bExisted)
	{
		if(NO!=bDir)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		return false;
	}
}

/**
 * @brief 检测指定目录是否存在
 * @param cPath 指定目录（编码：UTF-16）
 * @return true  目录存在
 * @return false 目录不存在
 */
bool osIsPathExist(const char16_t *cPath)
{
	if(nullptr==cPath)
	{
		return false;
	}

	char u8Path[256]={0x00};
	if(osConvertToUTF8(cPath,u8Path,256)<=0)
	{
		return false;
	}

	return osIsPathExist(u8Path);
}

/**
 * @brief 检测指定目录是否存在
 * @param cPath 指定目录（编码：UTF-32）
 * @return true  目录存在
 * @return false 目录不存在
 */
bool osIsPathExist(const char32_t *cPath)
{
	if(nullptr==cPath)
	{
		return false;
	}

	char u8Path[256]={0x00};
	if(osConvertToUTF8(cPath,u8Path,256)<=0)
	{
		return false;
	}

	return osIsPathExist(u8Path);
}

/**
 * @brief 读取文件
 * @param hFile                      文件句柄
 * @param lpBuffer                   数据缓冲区
 * @param nNumberOfBytesToRead       数据缓冲区字节数
 * @param lpNumberOfBytesRead        实际读取的字节数
 * @return true                      文件读取成功
 * @return false                     文件读取失败
 */
bool osReadFile(void *hFile,void *lpBuffer,const uint32_t nNumberOfBytesToRead,uint32_t *lpNumberOfBytesRead)
{
	if(nullptr==hFile||nullptr==lpBuffer||0==nNumberOfBytesToRead)
	{
		return false;
	}

	NSFileHandle *nsFileHandle=(__bridge NSFileHandle*)hFile;
	if(nil==nsFileHandle)
	{
		return false;
	}

	NSData *nsData=nil;
	if(@available(iOS 13.0,*))
	{
		NSError *nsError=nil;
		nsData=[nsFileHandle readDataUpToLength:nNumberOfBytesToRead error:&nsError];
	}
	else
	{
		nsData=[nsFileHandle readDataOfLength:nNumberOfBytesToRead];
	}
	if(nil==nsData)
	{
		return false;
	}

	uint32_t ui32Length=(uint32_t)[nsData length];
	ui32Length=ui32Length>nNumberOfBytesToRead?nNumberOfBytesToRead:ui32Length;

	memcpy(lpBuffer,[nsData bytes],ui32Length);
	// for HYM : to check real read count
	*lpNumberOfBytesRead = ui32Length;
	return ui32Length;
}

/**
 * @brief 写文件
 * @param hFile                     文件句柄
 * @param lpBuffer                  数据缓冲区
 * @param nNumberOfBytesToWrite     数据字节数
 * @param lpNumberOfBytesWritten    实际写入字节数
 * @return true                     写入成功
 * @return false                    写入失败
 * @note  安卓assets目录中的文件不支持写入操作
 */
bool osWriteFile(void *hFile,void *lpBuffer,const uint32_t nNumberOfBytesToWrite,uint32_t *lpNumberOfBytesWritten)
{
	if(nullptr==hFile||nullptr==lpBuffer||0==nNumberOfBytesToWrite)
	{
		return false;
	}

	NSFileHandle *nsFileHandle=(__bridge NSFileHandle*)hFile;
	if(nil==nsFileHandle)
	{
		return false;
	}

	NSData *nsData=[NSData dataWithBytes:lpBuffer length:nNumberOfBytesToWrite];
	if(nil==nsData)
	{
		return false;
	}

	BOOL bRet=NO;
	if(@available(iOS 13.0,*))
	{
		NSError *nsError=nil;
		bRet=[nsFileHandle writeData:nsData error:&nsError];
	}
	else
	{
		[nsFileHandle writeData:nsData];
		bRet=YES;
	}
	if(NO==bRet)
	{
		return false;
	}

	*lpNumberOfBytesWritten=(uint32_t)[nsData length];

	return true;
}

/**
 * @brief 打开指定文件
 * @param filename     文件名称（编码： UTF-8）
 * @param mode         打开模式（r w a b t +）
 * @return nullptr     打开失败
 * @return !nullptr    文件句柄
 * @note   如果当前为安卓系统，并且期望访问assets目录下文件，则需要将
 *         cFileName设置为如下格式"assets:目录"
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osFopen(const char *filename,const char *mode)
{
	if(nullptr==filename||nullptr==mode)
	{
		return nullptr;
	}

	bool bReadOnly=false;
	bool bCreateNew=true;
	if(0==osstrstr("r",mode))
	{
		bReadOnly=true;
		bCreateNew=false;
	}

	return osOpenFile(filename,bReadOnly,bCreateNew);
}

/**
 * @brief 打开指定文件
 * @param filename     文件名称（编码： UTF-16）
 * @param mode         打开模式（r w a b t +）
 * @return nullptr     打开失败
 * @return !nullptr    文件句柄
 * @note   如果当前为安卓系统，并且期望访问assets目录下文件，则需要将
 *         cFileName设置为如下格式"assets:目录"
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osFopen(const char16_t *filename,const char16_t *mode)
{
	if(nullptr==filename||nullptr==mode)
	{
		return nullptr;
	}

	char u8FileName[256]={0x00};
	if(osConvertToUTF8(filename,u8FileName,256)<=0)
	{
		return nullptr;
	}
	char u8Mode[20]={0x00};
	if(osConvertToUTF8(mode,u8Mode,20)<=0)
	{
		return nullptr;
	}

	return osFopen(u8FileName,u8Mode);
}

/**
 * @brief 打开指定文件
 * @param filename     文件名称（编码： UTF-32）
 * @param mode         打开模式（r w a b t +）
 * @return nullptr     打开失败
 * @return !nullptr    文件句柄
 * @note   如果当前为安卓系统，并且期望访问assets目录下文件，则需要将
 *         cFileName设置为如下格式"assets:目录"
 * @note   当文件处于安卓系统下的assets目录中时，只读，其它权限将被忽略
 */
void *osFopen(const char32_t *filename,const char32_t *mode)
{
	if(nullptr==filename||nullptr==mode)
	{
		return nullptr;
	}
	
	char u8FileName[256]={0x00};
	if(osConvertToUTF8(filename,u8FileName,256)<=0)
	{
		return nullptr;
	}
	char u8Mode[20]={0x00};
	if(osConvertToUTF8(mode,u8Mode,20)<=0)
	{
		return nullptr;
	}
	
	return osFopen(u8FileName,u8Mode);
}

/**
 * @brief 读取指定文件
 * @param buf            存储读取数据的空间
 * @param size           每个元素大小，以字节为单位
 * @param count          元素个数
 * @param filehandle     文件句柄
 * @return >0            实际读取的元素个数
 * @return <=0           读取失败
 * @note   如果当前为安卓系统，并且期望访问assets目录下文件，则需要将
 *         cFileName设置为如下格式"assets:目录"
 */
int32_t osFread(char *buf,const int32_t size,const int32_t count,void *filehandle)
{
	if(nullptr==buf||size<=0||count<=0||nullptr==filehandle)
	{
		return OSE_INVALID_PARAM;
	}

	uint32_t ui32BytesReaded=0;
	const bool bRet=osReadFile(filehandle,buf,count*size,&ui32BytesReaded);
	if(false==bRet)
	{
		return OSE_FAIL;
	}

	return (int32_t)ui32BytesReaded;
}

/**
 * @brief 将缓冲区中内容，写入文件中
 * @param buf              缓冲区
 * @param size             每个缓冲区元素尺寸
 * @param count            缓冲区中存储元素个数
 * @param filehandle       文件句柄
 * @return >0              实际写入文件元素个数
 * @return <=0             写入失败
 * @note 如果文件位于安卓assets目录下，则不支持此操作，assets目录只读
 */
int32_t osFwrite(const char *buf,const int32_t size,const int32_t count,void *filehandle)
{
	if(nullptr==buf||size<=0||count<=0||nullptr==filehandle)
	{
		return OSE_INVALID_PARAM;
	}

	uint32_t ui32BytesWrited=0;
	const bool bRet=osWriteFile(filehandle,(void*)buf,(uint32_t)count*size,&ui32BytesWrited);
	if(false==bRet)
	{
		return OSE_FAIL;
	}

	return (int32_t)ui32BytesWrited;
}

/**
 * @brief 冲洗流中的信息，强迫将缓冲区内的数据
 *        写回参数filehandle指定的文件中
 * @param hFile  文件句柄
 * @return  0    操作成功
 * @return !0    操作失败
 * @note 如果文件位于安卓assets目录下，则不支持此操作，assets目录只读
 */
int32_t osFflush(void *hFile)
{
	if(nullptr==hFile)
	{
		return -1;
	}

	NSFileHandle *nsFileHandle=(__bridge NSFileHandle*)hFile;
	if(nil==nsFileHandle)
	{
		return -1;
	}

	if (@available(iOS 13.0,*))
	{
		NSError *nsError=nil;
		BOOL bRet=[nsFileHandle synchronizeAndReturnError: &nsError];
		if (nil!=nsError||NO!=bRet)
		{
			return -1;
		}
	}
	else
	{
		[nsFileHandle synchronizeFile];
	}

	return 0;
}

/**
 * @brief 设置流filehandle的文件位置为给定的偏移offset，
 *        参数offset意味着从给定的seekmode位置查找的字
 *        节数。
 * @param filehandle     文件句柄 
 * @param offset         这是相对seekmode的偏移量，以字节为单位。
 * @param seekmode       这是表示开始添加偏移 offset 的位置。
 *                       SEEK_SET=0	文件的开头
 *                       SEEK_CUR=1	文件指针的当前位置
 *                       SEEK_END=2	文件的末尾
 * @return 0             成功
 * @return !0            失败
 * @note iOS系统目前只支持SEEK_SET的偏移，seekmode将被忽略
 * @note iOS 13.0 以上版本才支持此操作
 */
int32_t osFseek(void *filehandle,const int64_t offset,const int32_t seekmode)
{
	if(nullptr==filehandle||seekmode<0||seekmode>=3)
	{
		return OSE_INVALID_PARAM;
	}

	NSFileHandle *nsFileHandle=(__bridge NSFileHandle*)filehandle;
	if(nil==nsFileHandle)
	{
		return OSE_FAIL;
	}

	BOOL bRet=NO;
	if(@available(iOS 13.0,*))
	{
		NSError *nsError=nil;
		bRet=[nsFileHandle seekToOffset:(uint64_t)offset error:&nsError];
	}
	else
	{
		bRet=YES;
		[nsFileHandle seekToFileOffset:(uint64_t)offset];
	}
	if(NO==bRet)
	{
		return OSE_FAIL;
	}

	return 0;
}

/**
 * @brief 返回给定流filehandle的当前文件位置。
 * @param filehandle    文件句柄
 * @return -1           错误
 * @return !-1          返回位置标识符的当前位置值。
 * @note 如果文件位于安卓assets目录下，则不支持此操作。
 * @note iOS 13.0 以上版本才支持此操作
 */
int64_t osFtell(void *filehandle)
{
	if(nullptr==filehandle)
	{
		return OSE_FAIL;
	}

	NSFileHandle *nsFileHandle=(__bridge NSFileHandle*)filehandle;
	if(nil==nsFileHandle)
	{
		return OSE_FAIL;
	}

	uint64_t ui64Offset=0;
	BOOL bRet=NO;
	if(@available(iOS 13.0,*))
	{
		NSError *nsError=nil;
		bRet=[nsFileHandle getOffset:&ui64Offset error:&nsError];
	}
	else
	{
		bRet = YES;
		ui64Offset = [nsFileHandle offsetInFile];
	}
	if(NO==bRet)
	{
		return OSE_FAIL;
	}

	return (int64_t)ui64Offset;
}

/**
 * @brief 从指定的流filehandle读取一行，并把它存储在buf所指向的字符串内
 *        当读取 (n-1) 个字符时，或者读取到换行符时，或者到达文件末尾时，
 *        它会停止，具体视情况而定。
 * @param buf              这是指向一个字符数组的指针，该数组存储了要读取的字符串。
 * @param size             这是要读取的最大字符数（包括最后的空字符）。通常是使用
 *                         以buf传递的数组长度。
 * @param filehandle       这是指向 FILE 对象的指针，该 FILE 对象标识了要从中读
 *                         取字符的流。
 * @return nullptr         读取失败
 * @return !nullptr        该函数返回相同的buf参数
 * @note 如果文件位于安卓assets目录下，则不支持此操作。
 * @note iOS暂不支持此操作
 */
char *osFgets(char *buf,const int32_t size,void *filehandle)
{
	return nullptr; // iOS不支持此操作
}

/**
 * @brief 关闭流 filehandle。刷新所有的缓冲区。
 * @param filehandle       文件句柄
 * @return 0               操作成功
 * @return !0              操作失败
 */
int32_t osFclose(void *filehandle)
{
	if(nullptr==filehandle)
	{
		return OSE_FAIL;
	}
	
	NSFileHandle *nsFileHandle=(__bridge NSFileHandle*)filehandle;
	if(nil==nsFileHandle)
	{
		return OSE_FAIL;
	}

	if(@available(iOS 13.0,*))
	{
		NSError *nsError=nil;
		const BOOL bRet=[nsFileHandle closeAndReturnError:&nsError];
		if(NO==bRet)
		{
			return OSE_FAIL;
		}
		return OSE_OK;
	}
	else
	{
		[nsFileHandle closeFile];
		return OSE_OK;
	}
}

int64_t osFsize(void *filehandle)
{
	if(nullptr==filehandle)
	{
		return OSE_FAIL;
	}
	
	NSFileHandle *nsFileHandle=(__bridge NSFileHandle*)filehandle;
	if(nil==nsFileHandle)
	{
		return OSE_FAIL;
	}

	uint64_t uiCurOffset=0;
	uint64_t uiOffset=0;
	if(@available(iOS 13.0,*))
	{
		NSError *nsError=nil;
		bool bRet=[nsFileHandle getOffset:&uiCurOffset error:&nsError];
		if (NO == bRet)
		{
			return OSE_FAIL;
		}
		nsError=nil;
		bRet = [nsFileHandle seekToEndReturningOffset:&uiOffset error:&nsError];
		if (NO == bRet)
		{
			return OSE_FAIL;
		}
		nsError=nil;
		[nsFileHandle seekToOffset:uiCurOffset error:&nsError];
		return uiOffset;
	}
	else
	{
		uiCurOffset=[nsFileHandle offsetInFile];
		uiOffset=[nsFileHandle seekToEndOfFile];
		[nsFileHandle seekToFileOffset:uiCurOffset];
		return uiOffset;
	}

}

#endif // IOS || MAC 

//___________________________________________文件结束____________________________________________
